commonlibsse_ng\re\n/
NiMatrix3.rs1use crate::re::NiPoint3::NiPoint3;
2use core::f32::consts::PI;
3
4#[repr(C)]
6#[derive(Debug, Clone, Copy, PartialEq)]
7pub struct NiMatrix3 {
8 pub entry: [[f32; 3]; 3],
10}
11
12impl NiMatrix3 {
13 #[inline]
15 pub const fn new() -> Self {
16 Self { entry: [[1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0]] }
17 }
18
19 #[inline]
21 pub const fn from_vectors(x: NiPoint3, y: NiPoint3, z: NiPoint3) -> Self {
22 Self { entry: [[x.x, x.y, x.z], [y.x, y.y, y.z], [z.x, z.y, z.z]] }
23 }
24
25 #[inline]
27 pub const fn get_vector_x(&self) -> NiPoint3 {
28 NiPoint3::new(self.entry[0][0], self.entry[1][0], self.entry[2][0])
29 }
30
31 #[inline]
33 pub const fn get_vector_y(&self) -> NiPoint3 {
34 NiPoint3::new(self.entry[0][1], self.entry[1][1], self.entry[2][1])
35 }
36
37 #[inline]
39 pub const fn get_vector_z(&self) -> NiPoint3 {
40 NiPoint3::new(self.entry[0][2], self.entry[1][2], self.entry[2][2])
41 }
42
43 pub fn transpose(&self) -> Self {
45 let mut result = *self;
46 for i in 0..3 {
47 for j in 0..3 {
48 result.entry[i][j] = self.entry[j][i];
49 }
50 }
51 result
52 }
53
54 pub fn mul_matrix(&self, rhs: &Self) -> Self {
56 let mut result = Self::new();
57 for i in 0..3 {
58 for j in 0..3 {
59 result.entry[i][j] = (0..3).map(|k| self.entry[i][k] * rhs.entry[k][j]).sum();
60 }
61 }
62 result
63 }
64
65 pub fn mul_scalar(&self, scalar: f32) -> Self {
67 let mut result = *self;
68 for row in &mut result.entry {
69 for val in row.iter_mut() {
70 *val *= scalar;
71 }
72 }
73 result
74 }
75
76 pub fn mul_vector(&self, v: &NiPoint3) -> NiPoint3 {
78 NiPoint3 {
79 x: self.entry[0][2].mul_add(v.z, self.entry[0][0].mul_add(v.x, self.entry[0][1] * v.y)),
80 y: self.entry[1][2].mul_add(v.z, self.entry[1][0].mul_add(v.x, self.entry[1][1] * v.y)),
81 z: self.entry[2][2].mul_add(v.z, self.entry[2][0].mul_add(v.x, self.entry[2][1] * v.y)),
82 }
83 }
84
85 pub fn to_euler_xyz(&self) -> Option<NiPoint3> {
87 let y_angle = -self.entry[0][2].asin();
88 if y_angle.abs() < PI / 2.0 {
89 let x_angle = (-self.entry[1][2]).atan2(self.entry[2][2]);
90 let z_angle = (-self.entry[0][1]).atan2(self.entry[0][0]);
91 Some(NiPoint3::new(x_angle, y_angle, z_angle))
92 } else {
93 None
94 }
95 }
96
97 #[inline]
99 pub fn set_euler_xyz(&mut self, x: f32, y: f32, z: f32) {
100 *self = Self::from_euler_xyz(x, y, z);
101 }
102
103 pub fn from_euler_xyz(x: f32, y: f32, z: f32) -> Self {
105 let sin_x = x.sin();
106 let cos_x = x.cos();
107 let sin_y = y.sin();
108 let cos_y = y.cos();
109 let sin_z = z.sin();
110 let cos_z = z.cos();
111
112 Self {
113 entry: [
114 [cos_y * cos_z, cos_y * sin_z, -sin_y],
115 [
116 (sin_x * sin_y).mul_add(sin_z, cos_x * cos_z),
117 (sin_x * sin_y).mul_add(sin_z, cos_x * cos_z),
118 sin_x * cos_y,
119 ],
120 [
121 (cos_x * sin_y).mul_add(cos_z, sin_x * sin_z),
122 (cos_x * sin_y).mul_add(sin_z, -(sin_x * cos_z)),
123 cos_x * cos_y,
124 ],
125 ],
126 }
127 }
128}
129
130impl Default for NiMatrix3 {
131 #[inline]
132 fn default() -> Self {
133 Self::new()
134 }
135}
136
137impl core::ops::Mul for NiMatrix3 {
138 type Output = Self;
139
140 fn mul(self, rhs: Self) -> Self::Output {
141 self.mul_matrix(&rhs)
142 }
143}
144
145impl core::ops::Mul<NiPoint3> for NiMatrix3 {
146 type Output = NiPoint3;
147
148 fn mul(self, rhs: NiPoint3) -> Self::Output {
149 self.mul_vector(&rhs)
150 }
151}
152
153impl core::ops::Mul<f32> for NiMatrix3 {
154 type Output = Self;
155
156 fn mul(self, rhs: f32) -> Self::Output {
157 self.mul_scalar(rhs)
158 }
159}
160
161impl core::ops::Add for NiMatrix3 {
162 type Output = Self;
163
164 fn add(self, rhs: Self) -> Self::Output {
165 let mut result = self;
166 for i in 0..3 {
167 for j in 0..3 {
168 result.entry[i][j] += rhs.entry[i][j];
169 }
170 }
171 result
172 }
173}
174
175impl core::ops::Sub for NiMatrix3 {
176 type Output = Self;
177
178 fn sub(self, rhs: Self) -> Self::Output {
179 let mut result = self;
180 for i in 0..3 {
181 for j in 0..3 {
182 result.entry[i][j] -= rhs.entry[i][j];
183 }
184 }
185 result
186 }
187}
188
189#[cfg(test)]
190mod tests {
191 use super::*;
192
193 #[test]
194 fn test_matrix_operations() {
195 let m1 = NiMatrix3::from_euler_xyz(0.1, 0.2, 0.3);
196 let m2 = NiMatrix3::from_euler_xyz(0.3, 0.2, 0.1);
197 let result = m1 * m2;
198
199 let expected = NiMatrix3 {
200 entry: [
201 [1.146675, 0.42327216, -0.28814036],
202 [1.8687906, 0.9814126, 0.17860672],
203 [0.39051157, -0.28224778, 0.8589622],
204 ],
205 };
206 assert_eq!(result, expected);
207 }
208}